package com.hucii.app.net;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import android.content.Context;

import com.hucii.app.utils.UtilsLog;

public class SingleThreadDownloadManager implements Runnable {
	private static final String TAG = "SingleThreadDownloadManager";
	private static final int THREADID = 1;

	private Context context;
	private int downloadSize = 0;
	private int fileSize = 0;
	private File saveFile;
	private String downloadUrl;
	private DownloadListener listener;


	private static final int CONNECT_TIMEOUT = 10000;
	private static final int READ_TIMEOUT = 5000;

	public SingleThreadDownloadManager(Context context, DownloadListener listener, String downloadUrl, File fileSaveDir) {
		try {
			this.context = context;
			this.downloadUrl = downloadUrl;
			this.listener = listener;
			URL url = new URL(this.downloadUrl);
			if (!fileSaveDir.exists())
				fileSaveDir.mkdirs();
			HttpURLConnection conn = getHttpURLCon(url);
			conn.connect();
			printResponseHeader(conn);
			if (conn.getResponseCode() == 200) {
				this.fileSize = conn.getContentLength();
				if (this.fileSize <= 0)
					throw new RuntimeException("Unkown file size ");
				String filename = getFileName(conn);
				this.saveFile = new File(fileSaveDir, filename);
				if(saveFile.exists()) {
					this.downloadSize = (int) saveFile.length();
				}
				listener.onGetFileSize(this.fileSize);
			} else {
				throw new RuntimeException("server no response ");
			}


		} catch (Exception e) {
			e.printStackTrace();
			print(e.toString());
			throw new RuntimeException("don't connection this url");
		} finally {
		}
	}

	public HttpURLConnection getHttpURLCon(URL url) throws IOException {

		Proxy proxy = Proxy.NO_PROXY;
		if (Apn.M_USE_PROXY) {
			proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(Apn.M_APN_PROXY, Apn.M_APN_PORT));
		}

		HttpURLConnection conn = (HttpURLConnection) url.openConnection(proxy);
		conn.setConnectTimeout(CONNECT_TIMEOUT);
		conn.setReadTimeout(READ_TIMEOUT);
		conn.setRequestMethod("GET");
		conn.setRequestProperty(
				"Accept",
				"image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*");
		conn.setRequestProperty("Accept-Language", "zh-CN");
		conn.setRequestProperty("Charset", "UTF-8");
		conn.setRequestProperty(
				"User-Agent",
				"Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)");
		conn.setRequestProperty("Connection", "Keep-Alive");
		conn.setRequestProperty("Referer", downloadUrl);
		conn.setRequestProperty("Accept-Encoding","deflate");
		return conn;
	}

	private String getFileName(HttpURLConnection conn) {
		String filename = this.downloadUrl.substring(this.downloadUrl.lastIndexOf('/') + 1);
		if (filename == null || "".equals(filename.trim())) {
			for (int i = 0;; i++) {
				String mine = conn.getHeaderField(i);
				if (mine == null)
					break;
				if ("content-disposition".equals(conn.getHeaderFieldKey(i).toLowerCase())) {
					Matcher m = Pattern.compile(".*filename=(.*)").matcher(mine.toLowerCase());
					if (m.find())
						return m.group(1);
				}
			}
			filename = UUID.randomUUID() + ".tmp";
		}
		return filename;
	}

	public int download() throws Exception {
		try {
			new Thread(this).start();
		} catch (Exception e) {
			print(e.toString());
			throw new Exception("file download error");
		}
		return this.downloadSize;
	}

	public static Map<String, String> getHttpResponseHeader(HttpURLConnection http) {
		Map<String, String> header = new LinkedHashMap<String, String>();
		for (int i = 0;; i++) {
			String mine = http.getHeaderField(i);
			if (mine == null)
				break;
			header.put(http.getHeaderFieldKey(i), mine);
		}
		return header;
	}

	public static void printResponseHeader(HttpURLConnection http) {
		Map<String, String> header = getHttpResponseHeader(http);
		for (Map.Entry<String, String> entry : header.entrySet()) {
			String key = entry.getKey() != null ? entry.getKey() + ":" : "";
			print(key + entry.getValue());
		}
	}

	private static void print(String msg) {
		UtilsLog.e("exception", msg);
	}

	@Override
	public void run() {
		if (downloadSize < fileSize) {
			try {
				HttpURLConnection conn = getHttpURLCon(new URL(downloadUrl));
				int startPos = downloadSize;
				int endPos = fileSize;
				conn.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos);

				InputStream inStream = conn.getInputStream();
				byte[] buffer = new byte[1024];
				int offset = 0;
				print("Thread " + this + " start download from position " + startPos);
				RandomAccessFile threadfile = new RandomAccessFile(saveFile, "rwd");
				threadfile.seek(startPos);
				while ((offset = inStream.read(buffer, 0, 1024)) != -1) {
					threadfile.write(buffer, 0, offset);
					downloadSize += offset;
					if (listener != null)
						listener.onDownloadSize(this.downloadSize);
				}
				threadfile.close();
				inStream.close();

				if (downloadSize == this.fileSize) {
					listener.onDownloadFinish();
				}

				print("Thread " + THREADID + " download finish");
			} catch (Exception e) {
				print("Thread " + THREADID + ":" + e);
				listener.onDownloadFailure();
				return;
			}
		}
	}
}
